import { Injectable } from '@angular/core';
import { Action, State, StateContext } from '@ngxs/store';
import { SystemAction } from './system.action';
import { Clipboard } from '@angular/cdk/clipboard';
import { AppService } from '../../shared/services/app.service';
import { NzMessageService } from 'ng-zorro-antd/message';
import { DatePipe } from '@angular/common';
import { mergeMap, tap } from 'rxjs';
import * as _ from 'lodash';
import * as immutable from 'object-path-immutable';
import { uuid } from '../../utils/common';

export interface SystemStateModel {
  param: any;
  loading: boolean;
  list: any;
  configList: any;
}

@State<SystemStateModel>({
  name: 'system',
  defaults: {
    param: {},
    list: [],
    loading: false,
    configList: [],
  },
})
@Injectable({
  providedIn: 'root',
})
export class SystemState {

  constructor(
      private clipboard: Clipboard,
      private service: AppService,
      private message: NzMessageService,
  ) {
  }

  @Action(SystemAction.Init)
  Init(ctx: StateContext<SystemStateModel>) {
    ctx.patchState({
      loading: false,
      list: [],
      param: {},
    });
  }

  @Action(SystemAction.LoadBackupList)
  LoadBackupList(ctx: StateContext<SystemStateModel>) {
    let state = ctx.getState();
    let defaultParam = _.find(state.configList, s => s.isDefault);
    if (!defaultParam) return;
    return this.service.listFile(defaultParam.backupFolder).pipe(tap((r: any) => {
      ctx.patchState({list: r});
    }));
  }

  @Action(SystemAction.Backup)
  Backup(ctx: StateContext<SystemStateModel>) {
    ctx.patchState({loading: true});
    let state = ctx.getState();
    let defaultParam = _.find(state.configList, s => s.isDefault);
    const datePipe = new DatePipe('en-US');
    const currentDate = new Date();
    const formattedDate = datePipe.transform(currentDate, 'yyyy-MM-dd-HH-mm-ss');
    const zipName = `backup-${formattedDate}.zip`;
    return this.service.zip(zipName, defaultParam.saveFolder, defaultParam.backupFolder).pipe(tap({
      next: () => {
        this.message.success(`备份成功！`);
      },
      error: e => {
        this.message.error(`备份失败:${e}`);
      },
      complete: () => {
        ctx.patchState({loading: false});
      },
    }), mergeMap(() => ctx.dispatch(new SystemAction.LoadBackupList())));
  }

  @Action(SystemAction.Revert)
  Revert(ctx: StateContext<SystemStateModel>, {path}: SystemAction.Revert) {
    ctx.patchState({loading: true});
    let state = ctx.getState();
    let defaultParam = _.find(state.configList, s => s.isDefault);
    let zipName = `${defaultParam.backupFolder}/${path}`;
    return this.service.unzip(zipName, defaultParam.saveFolder).pipe(tap({
      next: () => {
        this.message.success(`还原成功！`);
      },
      error: e => {
        this.message.error(`还原失败:${e}`);
      },
      complete: () => {
        ctx.patchState({loading: false});
      },
    }));
  }

  @Action(SystemAction.ConfigNew)
  ConfigNew(ctx: StateContext<SystemStateModel>, {data}: SystemAction.ConfigNew) {
    let state = ctx.getState();
    data.id = uuid();
    ctx.setState(immutable.push(state, ['configList'], data));
  }

  @Action(SystemAction.ConfigSave)
  ConfigSave(ctx: StateContext<SystemStateModel>, {data}: SystemAction.ConfigSave) {
    let state = ctx.getState();
    let idx = _.findIndex(state.configList, (s: any) => s.id === data.id);
    ctx.setState(immutable.set(state, ['configList', idx], data));
  }

  @Action(SystemAction.SetDefaultConfig)
  SetDefaultConfig(ctx: StateContext<SystemStateModel>, {data}: SystemAction.SetDefaultConfig) {
    let state = ctx.getState();
    let oldIdx = _.findIndex(state.configList, (s: any) => s.isDefault === true);
    let newState = immutable.del(state, ['configList', oldIdx, 'isDefault']);
    let newIdx = _.findIndex(newState.configList, (s: any) => s.id === data.id);
    newState = immutable.set(newState, ['configList', newIdx, 'isDefault'], true);
    ctx.setState(newState);
  }

  @Action(SystemAction.DeleteConfig)
  DeleteConfig(ctx: StateContext<SystemStateModel>, {data}: SystemAction.DeleteConfig) {
    let state = ctx.getState();
    let idx = _.findIndex(state.configList, (s: any) => s.id === data.id);
    let newState = immutable.del(state, ['configList', idx]);
    ctx.setState(newState);
  }
}
